// on the owner of the GrabHelper. As long as there is at least one
// { modal: true } actor on the grab stack, the grab will be kept.
// When the last { modal: true } actor is ungrabbed, then the modal
- // will be dropped.
+ // will be dropped. A modal grab can fail if there is already a grab
+ // in effect from aother application; in this case the function returns
+ // false and nothing happens. Non-modal grabs can never fail.
//
// If @params contains { grabFocus: true }, then if you call grab()
// while the shell is outside the overview, it will set the stage
let newFocus = params.actor;
if (this.isActorGrabbed(params.actor))
- return;
+ return true;
- if (this._grabFocusCount == 0 && this._modalCount == 0)
- this._fullGrab(hadFocus, params.modal, params.grabFocus);
+ if (this._grabFocusCount == 0 && this._modalCount == 0) {
+ if (!this._fullGrab(hadFocus, params.modal, params.grabFocus))
+ return false;
+ }
params.savedFocus = focus;
this._grabStack.push(params);
this._grabFocusCount++;
_navigateActor(newFocus, hadFocus);
+
+ return true;
},
_fullGrab: function(hadFocus, modal, grabFocus) {
let metaDisplay = global.screen.get_display();
+ if (modal) {
+ if (!Main.pushModal(this._owner))
+ return false;
+ }
+
this._grabbedFromKeynav = hadFocus;
this._preGrabInputMode = global.stage_input_mode;
this._prevFocusedWindow = null;
- if (modal) {
- Main.pushModal(this._owner);
- }
-
if (grabFocus) {
this._prevFocusedWindow = metaDisplay.focus_window;
if (this._preGrabInputMode == Shell.StageInputMode.NONREACTIVE ||
this._keyFocusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
this._focusWindowChangedId = metaDisplay.connect('notify::focus-window', Lang.bind(this, this._focusWindowChanged));
}
+
+ return true;
},
// ignoreRelease:
let pointerWatcher = PointerWatcher.getPointerWatcher();
pointerWatcher.addWatch(TRAY_DWELL_CHECK_INTERVAL, Lang.bind(this, this._checkTrayDwell));
this._trayDwellTimeoutId = 0;
+ this._trayDwelling = false;
},
_checkTrayDwell: function(x, y) {
- // We only set up dwell timeout when the user is not hovering over the tray
- // (!this.actor.hover). This avoids bringing up the message tray after the
- // user clicks on a notification with the pointer on the bottom pixel
- // of the monitor.
- if (y == global.screen_height - 1 && !this.actor.hover) {
- if (this._trayDwellTimeoutId == 0)
+ if (y == global.screen_height - 1) {
+ // We only set up dwell timeout when the user is not hovering over the tray
+ // (!this.actor.hover). This avoids bringing up the message tray after the
+ // user clicks on a notification with the pointer on the bottom pixel
+ // of the monitor. The _trayDwelling variable is used so that we only try to
+ // fire off one tray dwell - if it fails (because, say, the user has the mouse down),
+ // we don't try again until the user moves the mouse up and down again.
+ if (!this._trayDwelling && !this.actor.hover && this._trayDwellTimeoutId == 0)
this._trayDwellTimeoutId = Mainloop.timeout_add(TRAY_DWELL_TIME,
- Lang.bind(this, this._trayDwellTimeout));
+ Lang.bind(this, this._trayDwellTimeout));
+ this._trayDwelling = true;
} else {
this._cancelTrayDwell();
+ this._trayDwelling = false;
}
},
},
_showTray: function() {
+ // Don't actually take a modal grab in the overview.
+ // Just add something to the grab stack that we can
+ // pop later.
+ if (!this._grabHelper.grab({ actor: this.actor,
+ modal: !this._overviewVisible,
+ onUngrab: Lang.bind(this, this._escapeTray) })) {
+ this._traySummoned = false;
+ return;
+ }
+
this._tween(this.actor, '_trayState', State.SHOWN,
{ y: -this.actor.height,
time: ANIMATION_TIME,
transition: 'easeOutQuad'
});
- // Don't actually take a modal grab in the overview.
- // Just add something to the grab stack that we can
- // pop later.
- this._grabHelper.grab({ actor: this.actor,
- modal: !this._overviewVisible,
- onUngrab: Lang.bind(this, this._escapeTray) });
-
// Don't move the windows up if we are in the overview,
// but show the tray in the ctrl+alt+tab list.
if (this._overviewVisible) {